import math

class Vector(object):
    def __init__(self, *args):
        self._comps = tuple(args[0]) if len(args) == 1 else tuple(args)

    @property
    def x(self):
        return self._comps[0]

    @property
    def y(self):
        return self._comps[1]

    @property
    def z(self):
        return self._comps[2]

    @property
    def squared_abs(self):
        return sum(a ** 2 for a in self)

    def __add__(self, other):
        return Vector(a + b for a, b in zip(self, other))

    def __sub__(self, other):
        return Vector(a - b for a, b in zip(self, other))

    def __mul__(self, other):
        return Vector(a * other for a in self)

    def __rmul__(self, other):
        return Vector(a * other for a in self)

    def __div__(self, other):
        return Vector(a / other for a in self)

    def __neg__(self):
        return Vector(-a for a in self)

    def __abs__(self):
        return math.sqrt(self.squared_abs)

    def __str__(self):
        return '[' + ', '.join(str(a) for a in self) + ']'

    def __repr__(self):
        return 'Vector(' + ', '.join(str(a) for a in self) + ')'

    def __cmp__(self, other):
        return cmp(self._comps, other._comps)

    def __hash__(self):
        return hash(self._comps)

    def __iter__(self):
        return iter(self._comps)

    def __nonzero__(self):
        return any(self)

    def __getitem__(self, index):
        return self._comps[index]

    def __len__(self):
        return len(self._comps)

class Shape(object):
    def distance_to(self, other):
        return math.sqrt(self.squared_distance_to(other))

class Rectangle(Shape):
    def __init__(self, min_, max_):
        self._min = Vector(min_)
        self._max = Vector(max_)

    @property
    def min_(self):
        return self._min

    @property
    def max_(self):
        return self._max

    @property
    def min_x(self):
        return self._min.x

    @property
    def min_y(self):
        return self._min.y

    @property
    def min_z(self):
        return self._min.z

    @property
    def max_x(self):
        return self._max.x

    @property
    def max_y(self):
        return self._max.y

    @property
    def max_z(self):
        return self._max.z

    @property
    def center(self):
        return (self.min_ + self.max_) / 2

    def __contains__(self, other):
        return self.contains(other)

    def contains(self, other):
        return self.contains_point(other)

    def contains_point(self, point):
        return all(min_a <= a and a < max_a
                   for min_a, a, max_a in zip(self.min_, point, self.max_))

    def intersects(self, other):
        return self.intersects_rectangle(other)

    def intersects_rectangle(self, other):
        return (self.min_x < other.max_x and other.min_x < self.max_x
                and self.min_y < other.max_y and other.min_y < self.max_y)

    def squared_distance_to(self, other):
        return self.squared_distance_to_rectangle(other)

    def squared_distance_to_rectangle(self, other):
        return (max(self.min_x - other.max_x,
                    other.min_x - self.max_x, 0) ** 2
                + max(self.min_y - other.max_y,
                      other.min_y - self.max_y, 0) ** 2)

    @property
    def bounds(self):
        return self

_offsets = dict(northwest = Vector(-1, 1),
                north = Vector(0, 1),
                northeast = Vector(1, 1),
                west = Vector(-1, 0),
                east = Vector(1, 0),
                southwest = Vector(-1, -1),
                south = Vector(0, -1),
                southeast = Vector(1, -1))

def direction_to_vector(dir):
    return _offsets[dir]

def is_horizontal_direction(dir):
    return dir in _offsets

def is_vertical_direction(dir):
    return dir in ('up', 'down')

def is_diagonal_direction(dir):
    return dir in ('northwest', 'northeast', 'southwest', 'southeast')
